package com.scheduling.inventory.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.scheduling.common.exception.BusinessException;
import com.scheduling.inventory.dto.MaterialInventoryDTO;
import com.scheduling.inventory.dto.MaterialInventoryQueryDTO;
import com.scheduling.inventory.entity.MaterialInventory;
import com.scheduling.inventory.mapper.MaterialInventoryMapper;
import com.scheduling.inventory.service.MaterialInventoryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 原料库存Service实现类
 *
 * @author 开发团队
 * @since 2025-05-29
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MaterialInventoryServiceImpl extends ServiceImpl<MaterialInventoryMapper, MaterialInventory>
        implements MaterialInventoryService {

    private final MaterialInventoryMapper materialInventoryMapper;

    @Override
    public IPage<MaterialInventoryDTO> getInventoryPage(MaterialInventoryQueryDTO queryDTO) {
        log.info("分页查询原料库存，查询条件：{}", queryDTO);

        Page<MaterialInventory> page = new Page<>(queryDTO.getCurrent(), queryDTO.getSize());
        IPage<MaterialInventory> inventoryPage = materialInventoryMapper.selectPageWithMaterial(page, queryDTO);

        // 转换为DTO
        IPage<MaterialInventoryDTO> dtoPage = inventoryPage.convert(this::convertToDTO);

        log.info("查询完成，共找到 {} 条记录", dtoPage.getTotal());
        return dtoPage;
    }

    @Override
    public MaterialInventoryDTO getInventoryById(String inventoryId) {
        log.info("根据库存ID查询库存信息：{}", inventoryId);

        if (StrUtil.isBlank(inventoryId)) {
            throw new BusinessException("库存ID不能为空");
        }

        MaterialInventory inventory = materialInventoryMapper.selectById(inventoryId);
        if (inventory == null) {
            throw new BusinessException("库存记录不存在");
        }

        return convertToDTO(inventory);
    }

    @Override
    public MaterialInventoryDTO getInventoryByMaterialId(String materialId) {
        log.info("根据原料ID查询库存信息：{}", materialId);

        if (StrUtil.isBlank(materialId)) {
            throw new BusinessException("原料ID不能为空");
        }

        MaterialInventory inventory = materialInventoryMapper.selectByMaterialId(materialId);
        if (inventory == null) {
            log.warn("原料 {} 不存在库存记录", materialId);
            return null;
        }

        return convertToDTO(inventory);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createInventory(MaterialInventoryDTO inventoryDTO) {
        log.info("新增原料库存：{}", inventoryDTO);

        // 检查是否已存在该原料的库存记录
        int count = materialInventoryMapper.countByMaterialId(inventoryDTO.getMaterialId());
        if (count > 0) {
            throw new BusinessException("该原料已存在库存记录，请直接更新库存数量");
        }

        MaterialInventory inventory = convertToEntity(inventoryDTO);
        boolean result = save(inventory);

        log.info("原料库存新增{}", result ? "成功" : "失败");
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateInventory(MaterialInventoryDTO inventoryDTO) {
        log.info("更新原料库存：{}", inventoryDTO);

        if (StrUtil.isBlank(inventoryDTO.getInventoryId())) {
            throw new BusinessException("库存ID不能为空");
        }

        MaterialInventory inventory = convertToEntity(inventoryDTO);
        boolean result = updateById(inventory);

        log.info("原料库存更新{}", result ? "成功" : "失败");
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteInventory(String inventoryId) {
        log.info("删除原料库存：{}", inventoryId);

        if (StrUtil.isBlank(inventoryId)) {
            throw new BusinessException("库存ID不能为空");
        }

        boolean result = removeById(inventoryId);
        log.info("原料库存删除{}", result ? "成功" : "失败");
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchDeleteInventory(List<String> inventoryIds) {
        log.info("批量删除原料库存，数量：{}", inventoryIds.size());

        if (inventoryIds == null || inventoryIds.isEmpty()) {
            throw new BusinessException("删除的库存ID列表不能为空");
        }

        boolean result = removeByIds(inventoryIds);
        log.info("批量删除原料库存{}", result ? "成功" : "失败");
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean adjustInventoryQuantity(String materialId, BigDecimal quantity, String reason) {
        log.info("调整原料库存数量，原料ID：{}，调整数量：{}，原因：{}", materialId, quantity, reason);

        MaterialInventory inventory = materialInventoryMapper.selectByMaterialId(materialId);
        if (inventory == null) {
            throw new BusinessException("原料库存记录不存在");
        }

        BigDecimal newQuantity = inventory.getQuantity().add(quantity);
        if (newQuantity.compareTo(BigDecimal.ZERO) < 0) {
            throw new BusinessException("调整后库存数量不能为负数");
        }

        inventory.setQuantity(newQuantity);
        boolean result = updateById(inventory);

        log.info("原料库存调整{}", result ? "成功" : "失败");
        return result;
    }

    @Override
    public List<MaterialInventoryDTO> getLowStockMaterials() {
        log.info("查询库存不足的原料列表");

        List<MaterialInventory> lowStockList = materialInventoryMapper.selectLowStockMaterials();
        List<MaterialInventoryDTO> dtoList = lowStockList.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());

        log.info("查询完成，共找到 {} 个库存不足的原料", dtoList.size());
        return dtoList;
    }

    @Override
    public boolean checkInventorySufficient(String materialId, BigDecimal requiredQuantity) {
        log.info("检查原料库存是否充足，原料ID：{}，所需数量：{}", materialId, requiredQuantity);

        MaterialInventory inventory = materialInventoryMapper.selectByMaterialId(materialId);
        if (inventory == null) {
            log.warn("原料 {} 不存在库存记录", materialId);
            return false;
        }

        boolean sufficient = inventory.getQuantity().compareTo(requiredQuantity) >= 0;
        log.info("库存检查结果：{}", sufficient ? "充足" : "不足");
        return sufficient;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean consumeInventory(String materialId, BigDecimal quantity, String reason) {
        log.info("消费原料库存，原料ID：{}，消费数量：{}，原因：{}", materialId, quantity, reason);

        if (quantity.compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException("消费数量必须大于0");
        }

        // 检查库存是否充足
        if (!checkInventorySufficient(materialId, quantity)) {
            throw new BusinessException("原料库存不足，无法消费");
        }

        return adjustInventoryQuantity(materialId, quantity.negate(), reason);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean replenishInventory(String materialId, BigDecimal quantity, String reason) {
        log.info("补充原料库存，原料ID：{}，补充数量：{}，原因：{}", materialId, quantity, reason);

        if (quantity.compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException("补充数量必须大于0");
        }

        return adjustInventoryQuantity(materialId, quantity, reason);
    }

    /**
     * 实体转DTO
     */
    private MaterialInventoryDTO convertToDTO(MaterialInventory entity) {
        MaterialInventoryDTO dto = new MaterialInventoryDTO();
        BeanUtil.copyProperties(entity, dto);
        return dto;
    }

    /**
     * DTO转实体
     */
    private MaterialInventory convertToEntity(MaterialInventoryDTO dto) {
        MaterialInventory entity = new MaterialInventory();
        BeanUtil.copyProperties(dto, entity);
        return entity;
    }
} 